package com.xuelang.pipeline.infrastructure.resource.repository;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import com.xuelang.pipeline.client.common.result.PageRecord;
import com.xuelang.pipeline.client.resource.dto.SpaceQuery;
import com.xuelang.pipeline.client.resource.enums.DefaultDataEnum;
import com.xuelang.pipeline.domain.resource.Space;
import com.xuelang.pipeline.domain.resource.repository.SpaceRepository;
import com.xuelang.pipeline.infrastructure.resource.converter.SpaceToSpaceDOConverter;
import com.xuelang.pipeline.infrastructure.resource.dataobject.ClusterDO;
import com.xuelang.pipeline.infrastructure.resource.dataobject.SpaceDO;
import com.xuelang.pipeline.infrastructure.resource.mapper.SpaceMapper;
import dm.jdbc.util.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import java.util.List;

/**
 * 空间仓库实现类
 *
 * @author xiwen.zxg
 * @since 2024/5/15
 */
@Slf4j
@Repository
public class SpaceRepositoryImpl implements SpaceRepository {

    @Autowired
    SpaceMapper spaceMapper;

    @Override
    public PageRecord<Space> pageList(long currentPage, long pageSize, SpaceQuery spaceQuery) {
        currentPage = currentPage < 1 ? 1 : currentPage;
        pageSize = pageSize < 1 ? 10 : pageSize;
        Page<Space> page = new Page<>(currentPage, pageSize);
        MPJLambdaWrapper<SpaceDO> wrapper = new MPJLambdaWrapper<SpaceDO>();
        if (spaceQuery != null) {
            wrapper.selectAll(SpaceDO.class)
                    .selectAs(ClusterDO::getName, Space::getClusterName)
                    .leftJoin(ClusterDO.class, ClusterDO::getUuid, SpaceDO::getClusterUuid)
                    .and(StrUtil.isNotBlank(spaceQuery.getCondition()), wp -> wp
                            .like(SpaceDO::getName, spaceQuery.getCondition()).or()
                            .like(SpaceDO::getCode, spaceQuery.getCondition()).or()
                            .like(SpaceDO::getNamespace, spaceQuery.getCondition()))
                    .apply(StrUtil.isNotBlank(spaceQuery.getStartDate()), "DATE_FORMAT(t.create_time,'%Y-%m-%d')>={0}", spaceQuery.getStartDate())
                    .apply(StrUtil.isNotBlank(spaceQuery.getStartDate()), "DATE_FORMAT(t.create_time,'%Y-%m-%d')<={0}", spaceQuery.getEndDate())
                    .orderByDesc(SpaceDO::getCreateTime);
        }
        spaceMapper.selectJoinPage(page, Space.class, wrapper);
        return new PageRecord<>(
                page.getCurrent(),
                page.getSize(),
                page.getTotal(),
                page.getPages(),
                page.getRecords());
    }

    @Override
    public List<Space> list(SpaceQuery spaceQuery) {
        MPJLambdaWrapper<SpaceDO> wrapper = new MPJLambdaWrapper<SpaceDO>();
        if (spaceQuery != null) {
            wrapper.selectAll(SpaceDO.class)
                    .selectAs(ClusterDO::getName, Space::getClusterName)
                    .leftJoin(ClusterDO.class, ClusterDO::getUuid, SpaceDO::getClusterUuid)
                    .and(StrUtil.isNotBlank(spaceQuery.getProjectCode()), wp -> wp
                            .eq(SpaceDO::getProjectCode, spaceQuery.getProjectCode()))
                    .and(StrUtil.isNotBlank(spaceQuery.getCondition()), wp -> wp
                            .like(SpaceDO::getName, spaceQuery.getCondition()).or()
                            .like(SpaceDO::getCode, spaceQuery.getCondition()).or()
                            .like(SpaceDO::getNamespace, spaceQuery.getCondition()))
                    .apply(StrUtil.isNotBlank(spaceQuery.getStartDate()), "DATE_FORMAT(t.create_time,'%Y-%m-%d')>={0}", spaceQuery.getStartDate())
                    .apply(StrUtil.isNotBlank(spaceQuery.getStartDate()), "DATE_FORMAT(t.create_time,'%Y-%m-%d')<={0}", spaceQuery.getEndDate())
                    .orderByDesc(SpaceDO::getCreateTime);
        }
        return spaceMapper.selectJoinList(Space.class, wrapper);
    }

    @Override
    public Boolean save(Space space) {
        return spaceMapper.insert(SpaceToSpaceDOConverter.INSTANCE.spaceToSpaceDO(space)) == 1;
    }

    @Override
    public Boolean update(Space space) {
        return spaceMapper.update(
                SpaceToSpaceDOConverter.INSTANCE.spaceToSpaceDO(space),
                Wrappers.lambdaQuery(SpaceDO.class)
                        .eq(SpaceDO::getUuid, space.getUuid())) == 1;
    }

    @Override
    public Boolean delete(String uuid) {
        return spaceMapper.delete(Wrappers.lambdaQuery(SpaceDO.class)
                .eq(SpaceDO::getUuid, uuid)) == 1;
    }

    @Override
    public Space query(String uuid) {
        SpaceDO spaceDO = spaceMapper.selectOne(Wrappers.lambdaQuery(SpaceDO.class).eq(SpaceDO::getUuid, uuid));
        return SpaceToSpaceDOConverter.INSTANCE.spaceDOToSpace(spaceDO);
    }

    @Override
    public Boolean existsSpaceByClusterUuid(String clusterUuid) {
        return spaceMapper.exists(Wrappers.lambdaQuery(SpaceDO.class).eq(SpaceDO::getClusterUuid, clusterUuid));
    }

    @Override
    public Space queryDefaultSpace() {
        MPJLambdaWrapper<SpaceDO> wrapper = new MPJLambdaWrapper<SpaceDO>();
        wrapper.eq(SpaceDO::getIsDefault, DefaultDataEnum.YES.getCode());
        return spaceMapper.selectJoinOne(Space.class, wrapper);
    }

    @Override
    public Boolean existsCode(String targetClusterUuid, String spaceCode) {
        return spaceMapper.exists(Wrappers.lambdaQuery(SpaceDO.class)
                .eq(SpaceDO::getClusterUuid, targetClusterUuid)
                .eq(SpaceDO::getCode, spaceCode));
    }

    @Override
    public Boolean existsName(String targetClusterUuid, String spaceCode, String spaceName) {
        List<SpaceDO> spaceDOS = spaceMapper.selectList(Wrappers.lambdaQuery(SpaceDO.class)
                .eq(SpaceDO::getClusterUuid, targetClusterUuid)
                .eq(SpaceDO::getName, spaceName));
        if (ObjectUtil.isEmpty(spaceDOS)) {
            return false;
        }
        return spaceDOS.stream().anyMatch(spaceDO -> !StringUtil.equals(spaceCode, spaceDO.getCode()));
    }
}
